package labox.innovation.gameserver.instancemanager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import labox.innovation.config.Config;
import labox.innovation.db.core.L2DatabaseFactory;
import labox.innovation.gameserver.ItemsAutoDestroy;
import labox.innovation.gameserver.ThreadPoolManager;
import labox.innovation.gameserver.model.FuzeWorld;
import labox.innovation.gameserver.model.L2ItemInstance;
import labox.innovation.gameserver.model.L2Object;
import labox.innovation.gameserver.model.Scene;
import labox.innovation.gameserver.templates.item.L2EtcItemType;
import labox.innovation.gameserver.timer.Timer;

/**
 * This class manage all items on ground
 * 
 * @version $Revision: $ $Date: $
 * @author DiezelMax - original idea
 * @author Enforcer - actual build
 */
public class ItemsOnGroundManager {

	private static final Logger _log = LoggerFactory.getLogger(ItemsOnGroundManager.class.getName());

	protected ArrayList<L2ItemInstance> _items;

	private ItemsOnGroundManager() {
		if (Config.SAVE_DROPPED_ITEM)
			_items = new ArrayList<L2ItemInstance>();
		if (Config.SAVE_DROPPED_ITEM_INTERVAL > 0)
			new Timer(Config.SAVE_DROPPED_ITEM_INTERVAL, true, new storeInDb()).start();
		load();
	}

	public static final ItemsOnGroundManager getInstance() {
		return SingletonHolder._instance;
	}

	private void load() {
		// If SaveDroppedItem is false, may want to delete all items previously stored to avoid add old items on reactivate
		if (!Config.SAVE_DROPPED_ITEM && Config.CLEAR_DROPPED_ITEM_TABLE)
			emptyTable();

		if (!Config.SAVE_DROPPED_ITEM)
			return;

		// if DestroyPlayerDroppedItem was previously  false, items curently protected will be added to ItemsAutoDestroy
		if (Config.DESTROY_DROPPED_PLAYER_ITEM) {
			Connection con = null;
			try {
				String str = null;
				if (!Config.DESTROY_EQUIPABLE_PLAYER_ITEM) //Recycle misc. items only
					str = "update itemsonground set drop_time=? where drop_time=-1 and equipable=0";
				else if (Config.DESTROY_EQUIPABLE_PLAYER_ITEM) //Recycle all items including equip-able
					str = "update itemsonground set drop_time=? where drop_time=-1";
				con = L2DatabaseFactory.getInstance().getConnection();
				PreparedStatement statement = con.prepareStatement(str);
				statement.setLong(1, System.currentTimeMillis());
				statement.execute();
				statement.close();
			} catch (Exception e) {
				_log.error("error while updating table ItemsOnGround ", Config.SERVER_ID, e);
			} finally {
				try {
					con.close();
				} catch (Exception e) {
				}
			}
		}

		//Add items to world
		Connection con = null;
		try {
			con = L2DatabaseFactory.getInstance().getConnection();
			Statement s = con.createStatement();
			ResultSet result;
			int count = 0;
			result = s.executeQuery("select object_id,item_id,count,enchant_level,x,y,z,drop_time,equipable from itemsonground");
			while (result.next()) {
				L2ItemInstance item = new L2ItemInstance(result.getInt(1), result.getInt(2));
				FuzeWorld.getInstance().enterWorld(item);
				if (item.isStackable() && result.getInt(3) > 1) //this check and..
					item.setCount(result.getInt(3));
				if (result.getInt(4) > 0) // this, are really necessary?
					item.setEnchantLevel(result.getInt(4));

				item.setIsVisible(true);

				item.spawnMe(result.getInt(7), result.getInt(5), result.getInt(6));//scene id,x,y

				item.setDropTime(result.getLong(8));

				_items.add(item);
				count++;
				// add to ItemsAutoDestroy only items not protected
				if (!Config.LIST_PROTECTED_ITEMS.contains(item.getItemId())) {
					if (result.getLong(8) > -1) {
						if ((Config.AUTODESTROY_ITEM_AFTER > 0) || (Config.HERB_AUTO_DESTROY_TIME > 0))
							ItemsAutoDestroy.getInstance().addItem(item);
					}
				}
			}
			result.close();
			s.close();
			if (count > 0)
				_log.info("ItemsOnGroundManager: restored " + count + " items.", Config.SERVER_ID);
			else
				_log.info("Initializing ItemsOnGroundManager.", Config.SERVER_ID);
		} catch (Exception e) {
			_log.error("error while loading ItemsOnGround ", Config.SERVER_ID, e);
			e.printStackTrace();
		} finally {
			try {
				con.close();
			} catch (Exception e) {
			}
		}
		if (Config.EMPTY_DROPPED_ITEM_TABLE_AFTER_LOAD)
			emptyTable();
	}

	public void save(L2ItemInstance item) {
		if (!Config.SAVE_DROPPED_ITEM)
			return;
		_items.add(item);
	}

	public void removeObject(L2Object item) {
		if (Config.SAVE_DROPPED_ITEM && _items != null) {
			_items.remove(item);
		}
	}

	public void saveInDb() {
		new storeInDb().run();
	}

	public void cleanUp() {
		_items.clear();
	}

	public void emptyTable() {
		Connection conn = null;
		try {
			conn = L2DatabaseFactory.getInstance().getConnection();
			PreparedStatement del = conn.prepareStatement("delete from itemsonground");
			del.execute();
			del.close();
		} catch (Exception e1) {
			_log.error("error while cleaning table ItemsOnGround ", Config.SERVER_ID, e1);
			e1.printStackTrace();
		} finally {
			try {
				conn.close();
			} catch (Exception e1) {
			}
		}
	}

	protected class storeInDb implements Runnable {
		@Override
		public void run() {
			if (!Config.SAVE_DROPPED_ITEM)
				return;

			emptyTable();

			if (_items.isEmpty()) {
				if (_log.isDebugEnabled())
					_log.warn("ItemsOnGroundManager: nothing to save...", Config.SERVER_ID);
				return;
			}

			for (L2ItemInstance item : _items) {
				if (item == null)
					continue;

				Connection con = null;
				try {
					con = L2DatabaseFactory.getInstance().getConnection();
					PreparedStatement statement = con.prepareStatement("insert into itemsonground(object_id,item_id,count,enchant_level,x,y,z,drop_time,equipable) values(?,?,?,?,?,?,?,?,?)");
					statement.setLong(1, item.getObjectId());
					statement.setInt(2, item.getItemId());
					statement.setLong(3, item.getCount());
					statement.setInt(4, item.getEnchantLevel());
					statement.setInt(5, item.getX());
					statement.setInt(6, item.getY());

					statement.setLong(8, item.getDropTime()); //item will be added to ItemsAutoDestroy
					if (item.isEquipable())
						statement.setLong(9, 1); //set equip-able
					else
						statement.setLong(9, 0);
					statement.execute();
					statement.close();
				} catch (Exception e) {
					_log.error("error while inserting into table ItemsOnGround ", Config.SERVER_ID, e);
					e.printStackTrace();
				} finally {
					try {
						con.close();
					} catch (Exception e) {
					}
				}
			}
			if (_log.isDebugEnabled())
				_log.warn("ItemsOnGroundManager: " + _items.size() + " items on ground saved", Config.SERVER_ID);
		}
	}

	@SuppressWarnings("synthetic-access")
	private static class SingletonHolder {
		protected static final ItemsOnGroundManager _instance = new ItemsOnGroundManager();
	}
}
